home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 1.toast / pc / sample code / devices and hardware / disks / basicdiskimage / moreisbetterbits / moredisks.c next >
Encoding:
Text File  |  2000-06-23  |  20.4 KB  |  721 lines

  1. /*
  2.     File:        MoreDisks.c
  3.  
  4.     Contains:    General disk driver utility routines.
  5.  
  6.     Written by:    Quinn
  7.  
  8.     Copyright:    Copyright © 1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.  
  20.          <2>      7/5/99    Quinn   Added MoreIsDriveCDROM.  Fixed bug in MoreGetDriveRefNum where
  21.                                     it was calling MoreUTFindDrive rather than MoreUTFindDriveQ, and
  22.                                     hence failing on disks controlled by foreign file systems.
  23.          <1>     16/3/99    Quinn   First checked in.
  24. */
  25.  
  26. /////////////////////////////////////////////////////////////////
  27.  
  28. // MoreIsBetter Setup
  29.  
  30. #include "MoreSetup.h"
  31.  
  32. // Mac OS Interfaces
  33.  
  34. #include <Devices.h>
  35. #include <DriverGestalt.h>
  36. #include <Gestalt.h>
  37. #include <FSM.h>
  38. #include <Disks.h>
  39. #include <StringCompare.h>
  40.  
  41. // MIB Prototypes
  42.  
  43. #include "TradDriverLoaderLib.h"
  44. #include "MoreInterfaceLib.h"
  45. #include "MoreMemory.h"
  46.  
  47. // Our Prototypes
  48.  
  49. #include "MoreDisks.h"
  50.  
  51. /////////////////////////////////////////////////////////////////
  52. #pragma mark ----- Basic Disk Driver Utilities -----
  53.  
  54. extern pascal DriveFlagsPtr MoreGetDriveFlags(DrvQElPtr drvQEl)
  55.     // See comment in interface part.
  56. {
  57.     MoreAssertQ(drvQEl != nil);
  58.  
  59.     return ((DriveFlagsPtr) drvQEl) - 1;
  60. }
  61.  
  62. extern pascal OSErr MoreUTFindDriveQ(SInt16 drive, DrvQElPtr *foundDrvQEl)
  63.     // See comment in interface part.
  64. {
  65.     OSErr err;
  66.     UInt32 fsmVers;
  67.  
  68.     MoreAssertQ(drive > 0);
  69.     MoreAssertQ(foundDrvQEl != nil);
  70.     
  71.     // Check to see whether we have a useful version of FSM.  Versions of FSM
  72.     // prior to 1.2 do not support the documented FSM API, so we just treat
  73.     // them as if FSM wasn't installed.
  74.     
  75.     if ((Gestalt(gestaltFSMVersion, (SInt32 *) &fsmVers) == noErr) && (fsmVers >= 0x0120)) {
  76.  
  77.         // We have FSM, let's call its version of UTFindDrive,
  78.         // and handle the weirdo error we get for non-HFS disks.
  79.  
  80.         err = MoreUTFindDrive(drive, foundDrvQEl);
  81.         if (err == extFSErr) {
  82.             err = noErr;
  83.         }
  84.     } else {
  85.         DrvQElPtr thisDrv;
  86.     
  87.         // No FSM, let's go poking around in low memory )-:
  88.         
  89.         *foundDrvQEl = nil;
  90.  
  91.         thisDrv = (DrvQElPtr) GetDrvQHdr()->qHead;
  92.         while (thisDrv != nil && *foundDrvQEl == nil) {
  93.             if (thisDrv->dQDrive == drive) {
  94.                 *foundDrvQEl = thisDrv;
  95.             } else {
  96.                 thisDrv = (DrvQElPtr) thisDrv->qLink;
  97.             }
  98.         }
  99.         if (*foundDrvQEl == nil) {
  100.             err = nsDrvErr;
  101.         } else {
  102.             err = noErr;
  103.         }
  104.     }
  105.     
  106.     return err;
  107. }
  108.  
  109. extern pascal DrvQElPtr MoreGetIndDrive(SInt16 index)
  110.     // See comment in interface part.
  111. {
  112.     DrvQElPtr thisDrv;
  113.     SInt16    thisDrvIndex;
  114.  
  115.     MoreAssertQ(index > 0);
  116.     
  117.     thisDrvIndex = 1;
  118.     thisDrv = (DrvQElPtr) GetDrvQHdr()->qHead;
  119.     while (thisDrv != nil && thisDrvIndex != index) {
  120.         thisDrvIndex += 1;
  121.         thisDrv = (DrvQElPtr) thisDrv->qLink;
  122.     }
  123.     return thisDrv;
  124. }
  125.  
  126. extern pascal SInt16 MoreFindFreeDriveNumber(SInt16 firstDrive)
  127.     // See comment in interface part.
  128. {
  129.     SInt16 candidate;
  130.     DrvQElPtr junkDrvQElPtr;
  131.     
  132.     MoreAssertQ(firstDrive >= 5);
  133.     
  134.     candidate = firstDrive;
  135.     while ( MoreUTFindDriveQ(candidate, &junkDrvQElPtr) == noErr ) {
  136.         candidate += 1;
  137.     }
  138.     
  139.     // This post condition checks that we didn't wrap
  140.     // around to a negative drive number.
  141.  
  142.     MoreAssertQ(candidate >= 5);
  143.  
  144.     return candidate;
  145. }
  146.  
  147. extern pascal OSErr MoreRemoveDrive(DrvQElPtr drvQEl)
  148.     // See comment in interface part.
  149. {
  150.     OSStatus err;
  151.     
  152.     if ( MoreVolumeMountedOnDrive(drvQEl->dQDrive, false) == 0 ) {
  153.         err = Dequeue( (QElemPtr) drvQEl, GetDrvQHdr());
  154.     } else {
  155.         err = volOnLinErr;
  156.     }
  157.     return err;
  158. }
  159.  
  160. extern pascal DriverRefNum MoreGetDriveRefNum(SInt16 drive)
  161.     // See comment in interface part.
  162. {
  163.     DrvQElPtr foundDrvQEl;
  164.  
  165.     MoreAssertQ(drive > 0);
  166.     
  167.     if ( MoreUTFindDriveQ(drive, &foundDrvQEl) == noErr) {
  168.         return foundDrvQEl->dQRefNum;
  169.     } else {
  170.         return 0;
  171.     }
  172. }
  173.  
  174. static pascal Boolean MoreDriveSupportsDriverGestaltInternal(DriverRefNum refNum)
  175.     // An internal version of MoreDriveSupportsDriverGestalt that allows
  176.     // you to pass in the refNum and the drive number.  You can pass
  177.     // in 0 for either refNum or drive (but not both) and the routine
  178.     // will do the appropriate mapping.
  179. {
  180.     OSErr junk;
  181.     DriverFlags driverFlags;
  182.     
  183.     junk = TradGetDriverInformation(refNum, nil, &driverFlags, nil, nil);
  184.     MoreAssertQ(junk == noErr);
  185.     return TradDriverGestaltIsOn(driverFlags);
  186. }
  187.  
  188. extern pascal Boolean MoreDriveSupportsDriverGestalt(SInt16 drive)
  189.     // See comment in interface part.
  190. {
  191.     return MoreDriveSupportsDriverGestaltInternal(MoreGetDriveRefNum(drive));
  192. }
  193.  
  194. static pascal Boolean MoreDriveSupportFileExchangeInternal(DriverRefNum refNum, SInt16 drive)
  195.     // An internal version of MoreDriveSupportFileExchange that allows
  196.     // you to pass in the refNum and the drive number.  You can pass
  197.     // in 0 for either refNum or drive (but not both) and the routine
  198.     // will do the appropriate mapping.
  199. {
  200.     DriverGestaltParam pb;
  201.     Boolean result;
  202.  
  203.     MoreAssertQ( (refNum < 0 && drive >= 0 && (drive == 0 || MoreGetDriveRefNum(drive) == refNum)) ||
  204.                  (refNum == 0 && drive > 0) );
  205.     
  206.     if (refNum == 0) {
  207.         refNum = MoreGetDriveRefNum(drive);
  208.     }
  209.     
  210.     result = false;
  211.     if ( MoreDriveSupportsDriverGestaltInternal(refNum) ) {
  212.         pb.ioVRefNum = drive;
  213.         pb.ioCRefNum = refNum;
  214.         pb.csCode = kDriverGestaltCode;
  215.         pb.driverGestaltSelector = kdgAPI;
  216.  
  217.         if ( PBStatusSync((ParmBlkPtr) &pb) == noErr 
  218.                 && GetDriverGestaltAPIResponse(&pb)->partitionCmds & 0x01 ) {
  219.             result = true;
  220.         }
  221.     }
  222.     return result;
  223. }
  224.  
  225. extern pascal Boolean MoreDriveSupportFileExchange(SInt16 drive)
  226.     // See comment in interface part.
  227. {
  228.     MoreAssertQ(drive > 0);
  229.     return MoreDriveSupportFileExchangeInternal(0, drive);
  230. }
  231.  
  232. // This is the number of format list entries we allocate when issuing
  233. // the return format list status call.  There's no way we can calculate
  234. // the "correct" number, but this should be more than enough.
  235.  
  236. enum {
  237.     kFormatListEntryCount = 16
  238. };
  239.  
  240. extern pascal OSErr MoreGetDriveSize(SInt16 drive, UInt32 *sizeInBlocks)
  241.     // See comment in interface part.
  242. {
  243.     OSErr err;
  244.     DrvQElPtr drvQEl;
  245.     CntrlParam pb;
  246.     FormatListRec formatList[kFormatListEntryCount];
  247.     SInt16 formatIndex;
  248.     Boolean foundFormat;
  249.     Str255 driverName;
  250.     DrvSts status;
  251.     
  252.     MoreAssertQ(drive > 0);
  253.     MoreAssertQ(sizeInBlocks != nil);
  254.  
  255.     // Start by finding the drive queue element for
  256.     // the drive, and by making sure that there's a disk
  257.     // in the drive.
  258.     
  259.     err = MoreUTFindDriveQ(drive, &drvQEl);
  260.     if (err == noErr) {
  261.         if ( MoreGetDriveFlags(drvQEl)->diskInPlace <= 0 ) {
  262.             err = offLinErr;
  263.         }
  264.     }
  265.  
  266.     // Wow, this is harder than it should be, all because of the
  267.     // silly ".Sony" driver.  The basic problem is that
  268.     // the ".Sony" driver doesn't store the disk size in the
  269.     // drive queue element like every other disk drive on the
  270.     // planet.  The solution is a three step process as described
  271.     // in the comments below.
  272.     
  273.     if (err == noErr) {
  274.  
  275.         // Step 1.  If the driver supports the kReturnFormatList status call,
  276.         //              use it to get a list of formats for the drive and then
  277.         //            return the format marked as current.
  278.  
  279.         pb.ioNamePtr = nil;
  280.         pb.ioVRefNum = drvQEl->dQDrive;
  281.         pb.ioCRefNum = drvQEl->dQRefNum;
  282.         pb.csCode = kReturnFormatList;
  283.         pb.csParam[0] = kFormatListEntryCount;
  284.         *((FormatListRec **) &pb.csParam[1]) = formatList;
  285.         err = PBStatusSync( (ParmBlkPtr) &pb);
  286.         if (err == noErr) {
  287.             foundFormat = false;
  288.             for (formatIndex = 0; formatIndex < pb.csParam[0]; formatIndex++) {
  289.                 if ((formatList[formatIndex].formatFlags & diCIFmtFlagsCurrentMask) != 0) {
  290.                     *sizeInBlocks = formatList[formatIndex].volSize;
  291.                     foundFormat = true;
  292.                 }
  293.             }
  294.             if ( ! foundFormat ) {
  295.  
  296.                 // Hmmm, this isn't good.  The disk driver returned a format
  297.                 // list but none of the formats were marked as "current".
  298.                 // We handle this correctly but, in debug builds, we'll also
  299.                 // drop into MacsBug, just to let you know this is happening.
  300.  
  301.                 MoreAssertQ(false);
  302.                 err = paramErr;
  303.             }
  304.         } else {
  305.         
  306.             // ••• The logic here is slightly screwed up.  The problem is that
  307.             // I can't tell whether the kReturnFormatList call failed because
  308.             // the driver just doesn't support it, or because the driver failed
  309.             // to get the information for some other reason.  If that driver
  310.             // happens to be the ".Sony" driver, I'm going to take a wrong step
  311.             // next.
  312.             //
  313.             // For example, say that there's a 1.4MB disk in the floppy drive
  314.             // and I call kReturnFormatList and it fails with an error because
  315.             // of a cosmic ray.  I then test the driver name, find that it's
  316.             // ".Sony", call DriveStatus, and then return noErr with a size
  317.             // of either 400KB or 800KB.  Not good.
  318.             // 
  319.             // You might think this is an unlikely occurence, but it's exactly
  320.             // what happens when there's no disk in the floppy drive.  I've
  321.             // special-cased that away above, but the general problem still stands.
  322.             // 
  323.             // What are the alternatives?  I could special case the error
  324.             // result from kReturnFormatList and only run this code if I get
  325.             // statusErr.  But can you guarantee that all ".Sony" drives
  326.             // return statusErr for an unrecognised status code?  I thought not.
  327.             // Beyond that, I can't think of any options.  So this code
  328.             // stands.  It's probably never going to bite anyone, but it's
  329.             // worth noting here, just in case.  Besides, this is what
  330.             // the equivalent routine in MoreFiles does (-:
  331.             //
  332.             // -- Quinn, 3 Mar 1999
  333.  
  334.             // Step 2.    If that doesn't work, then look at the driver.  If it's
  335.             //            the ".Sony" driver (and this will be a really old ".Sony" driver
  336.             //            because new ones support kReturnFormatList), special case
  337.             //            the possible media types.
  338.  
  339.             err = TradGetDriverInformation(drvQEl->dQRefNum, nil, nil, driverName, nil);
  340.             if (err == noErr) {
  341.                 if ( EqualString(driverName, "\p.Sony", false, true) ) {
  342.                     err = DriveStatus(drvQEl->dQDrive, &status);
  343.                     if (err == noErr) {
  344.                         if ( status.twoSideFmt == 0 ) {
  345.                             *sizeInBlocks = 400 * 2;
  346.                         } else {
  347.                             *sizeInBlocks = 800 * 2;
  348.                         }
  349.                     }
  350.                 } else {
  351.  
  352.                     // Step 3.    If it's not the ".Sony" driver, get the size out of the
  353.                     //            drive queue element.
  354.  
  355.                     if (drvQEl->qType == 0) {
  356.  
  357.                         // Old style drive, with just 16 bits of size information
  358.                         // in dQDrvSz.
  359.  
  360.                         *sizeInBlocks = drvQEl->dQDrvSz;
  361.                     } else {
  362.                     
  363.                         // New style drive, with 32 bits of size information spread
  364.                         // between dQDrvSz and dQDrvSz2.
  365.                         
  366.                         *sizeInBlocks = (((UInt32 ) drvQEl->dQDrvSz2) * 65536) + (UInt32 ) drvQEl->dQDrvSz;
  367.                     }
  368.                 }
  369.             }
  370.         }
  371.     }
  372.     
  373.     return err;
  374. }
  375.  
  376. extern pascal SInt16 MoreVolumeMountedOnDrive(SInt16 drive, Boolean ejectedIsMounted)
  377.     // See comment in interface part.
  378. {
  379.     SInt16 result;
  380.     VCBPtr thisVCB;
  381.  
  382.     MoreAssertQ(drive > 0);
  383.  
  384.     // Get the VCB queue (in low memory) and walk it.
  385.     // We can't use UTLocateNextVCB because it will only
  386.     // iterate volumes by name, not return a complete list.
  387.     
  388.     result = 0;
  389.     thisVCB    = (VCBPtr) GetVCBQHdr()->qHead;
  390.     while (thisVCB != nil && result == 0) {
  391.         if (thisVCB->vcbDrvNum == drive ||
  392.                 (ejectedIsMounted &&
  393.                  thisVCB->vcbDrvNum == 0 &&
  394.                  thisVCB->vcbDRefNum == drive
  395.                 )
  396.            ) {
  397.             MoreAssertQ(thisVCB->vcbDrvNum == 0 || thisVCB->vcbDRefNum == MoreGetDriveRefNum(drive));
  398.             result = thisVCB->vcbVRefNum;
  399.         } else {
  400.             thisVCB = (VCBPtr) thisVCB->qLink;
  401.         }
  402.     }
  403.     
  404.     return result;
  405. }
  406.  
  407. extern pascal SInt16 MoreFirstDriveWithoutVolume(DriverRefNum refNum)
  408.     // See comment in interface part.
  409. {
  410.     Boolean found;
  411.     DrvQElPtr thisDrv;
  412.  
  413.     found = false;
  414.     thisDrv = (DrvQElPtr) GetDrvQHdr()->qHead;
  415.     while (thisDrv != nil && ! found) {
  416.         if (thisDrv->dQRefNum == refNum && MoreVolumeMountedOnDrive(thisDrv->dQDrive, false) == 0) {
  417.             found = true;
  418.         } else {
  419.             thisDrv = (DrvQElPtr) thisDrv->qLink;
  420.         }
  421.     }
  422.     if (found) {
  423.         return thisDrv->dQDrive;
  424.     } else {
  425.         return 0;
  426.     }
  427. }
  428.  
  429. extern pascal void MoreIsDriveCDROM(SInt16 drive, MoreDisksCDROMResponse *response)
  430.     // See comment in interface part.
  431. {
  432.     DriverRefNum refNum;
  433.     DriverFlags drvrFlags;
  434.     Str255 drvrName;
  435.     DriverGestaltParam pb;
  436.     
  437.     MoreAssertQ(drive > 0);
  438.     MoreAssertQ(response != nil);
  439.     
  440.     *response = kMoreDriveUnableToDetermineCDROM;
  441.     
  442.     refNum = MoreGetDriveRefNum(drive);
  443.     if (refNum != 0) {
  444.         if ( TradGetDriverInformation(refNum, nil, &drvrFlags, drvrName, nil) == noErr ) {
  445.         
  446.             // Step 1 -- if the driver supports driver gestalt, we
  447.             // exclusively rely on its response for the kdgDeviceType
  448.             // selector.
  449.             
  450.             if ( TradDriverGestaltIsOn(drvrFlags) ) {
  451.                 pb.ioVRefNum = drive;
  452.                 pb.ioCRefNum = refNum;
  453.                 pb.csCode = kDriverGestaltCode;
  454.                 pb.driverGestaltSelector = kdgDeviceType;
  455.  
  456.                 if ( PBStatusSync((ParmBlkPtr) &pb) == noErr ) {
  457.                     if (GetDriverGestaltDevTResponse(&pb)->deviceType == kdgCDType) {
  458.                         *response = kMoreDriveIsCDROM;
  459.                     } else {
  460.                         *response = kMoreDriveIsNotCDROM;
  461.                     }
  462.                 }
  463.             }
  464.             
  465.             // Step 2 -- if the above didn't work, we only say it's a CD-ROM
  466.             // if the driver is ".AppleCD".
  467.  
  468.             if (*response == kMoreDriveUnableToDetermineCDROM) {
  469.                 if ( EqualString(drvrName, "\p.AppleCD", false, true) ) {
  470.                        *response = kMoreDriveIsCDROM;
  471.                 } else if ( EqualString(drvrName, "\p.AFPTranslator", false, true) ) {
  472.                     // ".AFPTranslator" does not respond to Driver Gestalt,
  473.                     // which is pretty lame IMHO.  [Radar ID ]  Regardless,
  474.                     // we know it's not a CD-ROM.
  475.                        *response = kMoreDriveIsNotCDROM;
  476.                 } else if ( EqualString(drvrName, "\p.Sony", false, true) ) {
  477.                        *response = kMoreDriveIsNotCDROM;
  478.                 }
  479.             }
  480.         }
  481.     }
  482. }
  483.  
  484. /////////////////////////////////////////////////////////////////
  485. #pragma mark ----- File Exchange Control Call Interface -----
  486.  
  487. extern pascal OSErr MoreCreateNewDriveQueueElement(SInt16 driveToClone,
  488.                         UInt32 firstBlock, UInt32 sizeInBlocks,
  489.                         SInt16 *newDrive)
  490.     // See comment in interface part.
  491. {
  492.     OSErr err;
  493.     OSErr junk;
  494.     CntrlParam pb;
  495.     DrvQElPtr drvQEl;
  496.  
  497.     MoreAssertQ(driveToClone > 0);
  498.     MoreAssertQ(newDrive != nil);
  499.     
  500.     // First check that the driver supports the File Exchange
  501.     // control call interface.
  502.         
  503.     err = noErr;
  504.     if ( ! MoreDriveSupportFileExchange(driveToClone) ) {
  505.         err = controlErr;
  506.     }
  507.     
  508.     // Find the drive queue element associated with
  509.     // driveToClone.  This is an input parameter to
  510.     // kGetADrive.
  511.     
  512.     if (err == noErr) {    
  513.         err = MoreUTFindDriveQ(driveToClone, &drvQEl);
  514.     }
  515.     
  516.     // Make the kGetADrive call to the driver.  Because
  517.     // we pass a pointer to memory outside of the parameter
  518.     // block (drvQEl) and the driver might be a paging device,
  519.     // we must hold drvQEl (and make sure to unhold it later!).
  520.     
  521.     if (err == noErr) {
  522.         err = SafeHoldMemory(&drvQEl, sizeof(drvQEl));
  523.         if (err == noErr) {
  524.             pb.ioVRefNum = driveToClone;
  525.             pb.ioCRefNum = MoreGetDriveRefNum(driveToClone);
  526.             pb.csCode = kGetADrive;
  527.             *((DrvQElPtr **) &pb.csParam[0]) = &drvQEl;
  528.  
  529.             err = PBControlSync((ParmBlkPtr) &pb);
  530.             if (err == noErr) {
  531.                 *newDrive = drvQEl->dQDrive;
  532.             }
  533.             junk = SafeUnholdMemory(&drvQEl, sizeof(drvQEl));
  534.             MoreAssertQ(junk == noErr);
  535.         }
  536.     }
  537.     
  538.     // Now re-target the new drive to the partition on the
  539.     // disk specified by firstBlock and sizeInBlocks.  We do
  540.     // this in the create call because some disk drivers
  541.     // don't always inherit the partition information from
  542.     // the drive that was cloned.
  543.     
  544.     if (err == noErr) {
  545.         err = MoreSetDrivePartition(*newDrive, firstBlock, sizeInBlocks);
  546.     }
  547.     
  548.     return err;
  549. }
  550.  
  551. extern pascal OSErr MoreSetDrivePartition(SInt16 drive, UInt32 firstBlock, UInt32 sizeInBlocks)
  552.     // See comment in interface part.
  553. {
  554.     OSErr err;
  555.     CntrlParam pb;
  556.     DrvQElPtr drvQEl;
  557.  
  558.     MoreAssertQ(drive > 0);
  559.     
  560.     // First check that the driver supports the File Exchange
  561.     // control call interface.
  562.         
  563.     err = noErr;
  564.     if ( ! MoreDriveSupportFileExchange(drive) ) {
  565.         err = controlErr;
  566.     }
  567.     
  568.     // Find the drive queue element associated with
  569.     // drive.  This is an input parameter to
  570.     // kRegisterPartition.
  571.     
  572.     if (err == noErr) {    
  573.         err = MoreUTFindDriveQ(drive, &drvQEl);
  574.     }
  575.     
  576.     // Make the kRegisterPartition control call.  We
  577.     // don't need to hold any memory because all the
  578.     // parameters to this control call are entirely
  579.     // contained within the parameter block.
  580.  
  581.     if (err == noErr) {
  582.         pb.ioVRefNum = drive;
  583.         pb.ioCRefNum = MoreGetDriveRefNum(drive);
  584.         pb.csCode = kRegisterPartition;
  585.         *((DrvQElPtr *) &pb.csParam[0]) = drvQEl;
  586.         *((UInt32 *) &pb.csParam[2]) = firstBlock;
  587.         *((UInt32 *) &pb.csParam[4]) = sizeInBlocks;
  588.  
  589.         err = PBControlSync((ParmBlkPtr) &pb);
  590.     }
  591.     
  592.     // In the debug build, check that our changes stuck.
  593.     
  594.     #if MORE_DEBUG
  595.         if (err == noErr) {
  596.             OSErr debugErr;
  597.             UInt32 trueFirstBlock;
  598.             UInt32 trueSizeInBlocks;
  599.  
  600.             debugErr = MoreGetDrivePartition(drive, &trueFirstBlock, &trueSizeInBlocks);
  601.             MoreAssertQ(debugErr == noErr && trueSizeInBlocks == sizeInBlocks && trueFirstBlock == firstBlock);
  602.         }
  603.     #endif
  604.     
  605.     return err;
  606. }
  607.  
  608. extern pascal OSErr MoreGetDrivePartition(SInt16 drive, UInt32 *firstBlock, UInt32 *sizeInBlocks)
  609.     // See comment in interface part.
  610. {
  611.     OSErr err;
  612.     partInfoRec partInfo;
  613.     
  614.     MoreAssertQ(drive > 0);
  615.     MoreAssertQ(firstBlock != nil);
  616.     MoreAssertQ(sizeInBlocks != nil);
  617.  
  618.     err = MoreGetPartitionInfo(drive, &partInfo);
  619.     if (err == noErr) {
  620.         *firstBlock = partInfo.physPartitionLoc;
  621.         err = MoreGetDriveSize(drive, sizeInBlocks);
  622.     }
  623.     return err;
  624. }
  625.  
  626. extern pascal OSErr MoreGetPartitionInfo(SInt16 drive, partInfoRec *partInfo)
  627.     // See comment in interface part.
  628. {
  629.     OSErr err;
  630.     OSErr junk;
  631.     CntrlParam pb;
  632.     
  633.     MoreAssertQ(drive > 0);
  634.     MoreAssertQ(partInfo != nil);
  635.  
  636.     // First check that the driver supports the File Exchange
  637.     // control call interface.
  638.         
  639.     err = noErr;
  640.     if ( ! MoreDriveSupportFileExchange(drive) ) {
  641.         err = controlErr;
  642.     }
  643.  
  644.     // Make the kGetADrive call to the driver.  Because
  645.     // we pass a pointer to memory outside of the parameter
  646.     // block (partInfo) and the driver might be a paging device,
  647.     // we must hold partInfo (and make sure to unhold it later!).
  648.  
  649.     if (err == noErr) {    
  650.         err = SafeHoldMemory(partInfo, sizeof(*partInfo));
  651.         if (err == noErr) {
  652.             pb.ioVRefNum = drive;
  653.             pb.ioCRefNum = MoreGetDriveRefNum(drive);
  654.             pb.csCode = kGetPartInfo;
  655.             *((partInfoRec **) &pb.csParam[0]) = partInfo;
  656.  
  657.             err = PBStatusSync((ParmBlkPtr) &pb);
  658.             
  659.             junk = SafeUnholdMemory(partInfo, sizeof(*partInfo));
  660.             MoreAssertQ(junk == noErr);
  661.         }
  662.     }
  663.     
  664.     return err;
  665. }
  666.  
  667. #if 0
  668.  
  669. // •••
  670. // This code temporarily disable while I figure out what's going on.
  671. // -- Quinn, 3 Mar 1999
  672.  
  673. extern pascal OSErr MoreGetPartitionVolume(DriverRefNum refNum, const partInfoRec *partInfo, SInt16 *vRefNum)
  674.     // See comment in interface part.
  675. {
  676.     OSErr err;
  677.     OSErr junk;
  678.     CntrlParam pb;
  679.     
  680.     MoreAssertQ(refNum < 0);
  681.     MoreAssertQ(partInfo != nil);
  682.     MoreAssertQ(vRefNum != nil);
  683.  
  684.     // First check that the driver supports the File Exchange
  685.     // control call interface.
  686.         
  687.     err = noErr;
  688.     if ( ! MoreDriveSupportFileExchangeInternal(refNum, 0) ) {
  689.         err = controlErr;
  690.     }
  691.  
  692.     // Make the kGetPartitionStatus call to the driver.  Because
  693.     // we pass a pointer to memory outside of the parameter
  694.     // block (partInfo and vRefNum) and the driver might be a paging device,
  695.     // we must hold that memory (and make sure to unhold it later!).
  696.  
  697.     if (err == noErr) {    
  698.         err = SafeHoldMemory( (partInfoRec *) partInfo, sizeof(*partInfo));
  699.         if (err == noErr) {
  700.             err = SafeHoldMemory(vRefNum, sizeof(*vRefNum));
  701.             if (err == noErr) {
  702.                 pb.ioVRefNum = 0;
  703.                 pb.ioCRefNum = refNum;
  704.                 pb.csCode = kGetPartitionStatus;
  705.                 *((partInfoRec **) &pb.csParam[0]) = (partInfoRec *) partInfo;
  706.                 *((SInt16 **) &pb.csParam[2]) = vRefNum;
  707.  
  708.                 err = PBStatusSync((ParmBlkPtr) &pb);
  709.  
  710.                 junk = SafeUnholdMemory(vRefNum, sizeof(*vRefNum));
  711.                 MoreAssertQ(junk == noErr);
  712.             }
  713.             junk = SafeUnholdMemory( (partInfoRec *) partInfo, sizeof(*partInfo));
  714.             MoreAssertQ(junk == noErr);
  715.         }
  716.     }
  717.     return err;
  718. }
  719.  
  720. #endif
  721.